package cn.zyx.file.minio.controller;

import cn.zyx.common.GlobalAjaxJson;
import cn.zyx.common.GlobalExceptions;
import cn.zyx.common.utils.file.*;
import cn.zyx.file.minio.entity.Minio;
import cn.zyx.file.minio.entity.dto.UploadDto;
import cn.zyx.file.minio.entity.dto.WaterFileDto;
import cn.zyx.file.minio.serivce.MinioService;
import io.minio.BucketExistsArgs;
import io.minio.MakeBucketArgs;
import io.minio.MinioClient;
import io.minio.SetBucketPolicyArgs;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Base64;
import java.util.List;

@RestController
@RequestMapping("/minio")
public class MinioController {

    private static final Logger log = LoggerFactory.getLogger(MinioController.class);

    @Autowired
    private MinioClient minioClient;
    @Autowired
    private MinioService minioService;

    /**
     * 创建桶
     * @param bucketName
     * 列出存储桶（s3:ListBucket, s3:ListBucketMultipartUploads）
     * 获取存储桶位置（s3:GetBucketLocation）
     * 上传/下载/删除对象（s3:PutObject, s3:GetObject, s3:DeleteObject）
     * 管理分片上传（s3:AbortMultipartUpload, s3:ListMultipartUploadParts）
     * 允许所有用户（"AWS": ["*"]）访问存储桶（适用于公开或内部共享存储）
     * @return
     */
    @GetMapping("addMinioBucket")
    @ApiOperation(value = "创建桶")
    public GlobalAjaxJson addMinioBucket(String bucketName) {
        try {
            BucketExistsArgs btest2 = BucketExistsArgs.builder().bucket(bucketName).build();
            String sb = "{\"Version\":\"2012-10-17\"," +
                        "\"Statement\":[{" +
                            "\"Effect\":\"Allow\"," +
                            "\"Principal\":" + "{\"AWS\":[\"*\"]}," +
                            "\"Action\":[" +
                                "\"s3:ListBucket\"," +
                                "\"s3:ListBucketMultipartUploads\"," +
                                "\"s3:GetBucketLocation\"]," +
                             "\"Resource\":[\"arn:aws:s3:::" + bucketName + "\"]" +
                        "},{" +
                            "\"Effect\":\"Allow\"," +
                            "\"Principal\":{\"AWS\":[\"*\"]}," +
                            "\"Action\":[" +
                                "\"s3:PutObject\"," +
                                "\"s3:AbortMultipartUpload\"," +
                                "\"s3:DeleteObject\"," +
                                "\"s3:GetObject\"," +
                                "\"s3:ListMultipartUploadParts\"]," +
                            "\"Resource\":[\"arn:aws:s3:::" + bucketName + "/*\"]}]}";
            boolean existFlag = minioClient.bucketExists(btest2);
            // 存储桶不存在则创建
            if (!existFlag) {
                minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
                // 设置成公共状态的代码
                minioClient.setBucketPolicy(SetBucketPolicyArgs.builder().bucket(bucketName).config(sb).build());
                System.out.printf("%s,创建成功", bucketName);
                return GlobalAjaxJson.success(bucketName + ",创建成功");
            } else {
                System.out.printf("%s,已存在", bucketName);
                return GlobalAjaxJson.success(bucketName + ",已存在");
            }
        } catch (Exception e) {
            System.out.println("Error occurred: " + e.getMessage());
            return GlobalAjaxJson.error(e.getMessage());
        }
    }

    /**
     * 文件上传请求
     */
    @PostMapping("/upload")
    public GlobalAjaxJson upload(@RequestParam("file") MultipartFile file) {
        try {
            // 判断文件大小
            this.voidImgSize(file);
            // 上传并返回访问地址
            String url = minioService.uploadFile(file);
            Minio minio = new Minio();
            minio.setName(FileUtils.getName(url));
            minio.setUrl(url);
            String s = minioService.generatePresignedUrl(url);
            minio.setAppPath(s);
            minio.setPath(s);
            return GlobalAjaxJson.success().put("minio", minio);
        } catch (Exception e) {
            log.error("上传文件失败", e);
            return GlobalAjaxJson.error(e.getMessage());
        }
    }

    /**
     * base64文件上传请求
     */
    @PostMapping("/uploadBase64")
    public GlobalAjaxJson uploadBase64(@RequestBody UploadDto dto) throws Exception {
        Minio minio = new Minio();
        if (StringUtils.isBlank(dto.getFilePath())) {
            return GlobalAjaxJson.error("文件信息异常！");
        }
        String type = JudgePictureType(dto.getFilePath());
        if (type.equals("undifend")) {
            return GlobalAjaxJson.error("文件类型有误！");
        }
        InputStream inputStream = ImageBase64Utils.base64ToImageFile(dto.getFilePath());
        String url = minioService.uploadBase64(inputStream);
        minio.setName(FileUtils.getName(url));
        minio.setUrl(url);
        String s = minioService.generatePresignedUrl(url);
        minio.setAppPath(s);
        minio.setPath(s);
        return GlobalAjaxJson.success().put("minio", minio);
    }

    /**
     * 批量上传
     * @param files
     * @return
     * @throws Exception
     */
    @PostMapping("uploadList")
    public GlobalAjaxJson uploadList(@RequestParam("file") List<MultipartFile> files) throws Exception {
        return GlobalAjaxJson.success().put("data", minioService.uploadList(files));
    }

    /**
     * 文件删除请求
     *
     * @param filePath 文件路径
     * @return
     */
    @GetMapping("deleteFile")
    public GlobalAjaxJson deleteFile(@RequestParam("filePath") String filePath) {
        try {
            if (StringUtils.isNotBlank(filePath)) {
                minioService.deleteFile(filePath);
            }
            return GlobalAjaxJson.success();
        } catch (Exception e) {
            log.error("上传文件失败", e);
            return GlobalAjaxJson.error(e.getMessage());
        }
    }

    /**
     * 根据文件名获取全路径
     *
     * @param filePath 获取全路径
     * @return 文件访问链接
     */
    @GetMapping("generatePresignedUrl")
    public GlobalAjaxJson generatePresignedUrl(String filePath) {
        try {
            String url = minioService.generatePresignedUrl(filePath);
            return GlobalAjaxJson.success(url);
        } catch (Exception e) {
            log.error("上传获取失败", e);
            return GlobalAjaxJson.error(e.getMessage());
        }
    }


    /**
     * 获取图片
     * @param filePath
     * @return
     */
    @GetMapping("getBatchImg")
    @ApiModelProperty(value = "批量获取图片")
    public GlobalAjaxJson getBatchImg(String filePath) {
        try {
            List<Minio> result = new ArrayList<>();
            List<String> pathList = new ArrayList<>();
            if (StringUtils.isNotEmpty(filePath)) {
                pathList = Arrays.asList(filePath.split(","));
            }
            for (String path : pathList) {
                String url = minioService.generatePresignedUrl(path);
                Minio minio = new Minio();
                minio.setName(path);
                minio.setUrl(url);
                minio.setPath(url);
                minio.setAppPath(minioService.generatePresignedUrlApp(path));
                result.add(minio);
            }
            return GlobalAjaxJson.success().put("data", result);
        } catch (Exception e) {
            log.error("上传获取失败", e);
            return GlobalAjaxJson.error(e.getMessage());
        }
    }


    /**
     * 获取图片
     * @param filePath
     * @return
     */
    @GetMapping("getBatchImgSource")
    @ApiModelProperty(value = "批量获取图片")
    public GlobalAjaxJson getBatchImgSource(String filePath) {
        try {
            List<Minio> result = new ArrayList<>();
            List<String> pathList = new ArrayList<>();
            if (StringUtils.isNotEmpty(filePath)) {
                pathList = Arrays.asList(filePath.split(","));
            }
            for (String path : pathList) {
                String url = minioService.generatePresignedUrl(path);
                Minio Minio = new Minio();
                Minio.setName(path);
                Minio.setUrl(path);
                Minio.setPath(url);
                Minio.setAppPath(minioService.generatePresignedUrlApp(path));
                result.add(Minio);
            }
            return GlobalAjaxJson.success().put("data", result);
        } catch (Exception e) {
            log.error("上传获取失败", e);
            return GlobalAjaxJson.error(e.getMessage());
        }
    }

    /**
     * 根据图片地址添加水印并上传minio
     * @param dto srcImgPath-场景图片路径-后置摄像头
     * @param dto srcImgPathUser-人物图片路径-前置摄像头
     * @param dto itemName-事项
     * @param dto taskName-场景
     * @param dto address-地址
     * @return
     */
    @PostMapping("uploadFiveImg")
    public GlobalAjaxJson uploadFiveImg(@RequestBody WaterFileDto dto) {
        try {
            if (CollectionUtils.isNotEmpty(dto.getSrcImgPathList())) {
                //批量文件返回
            } else if (StringUtils.isNotBlank(dto.getSrcImgPath())) {
                List<String> list = new ArrayList<>();
                list.add(dto.getSrcImgPath());
                dto.setSrcImgPathList(list);
            } else {
                return GlobalAjaxJson.error("图片地址不能为空！");
            }
            List<Minio> fileList = new ArrayList<>();
            for (String srcImgPath : dto.getSrcImgPathList()) {
                String srcImgPathUser = minioService.generatePresignedUrl(dto.getSrcImgPathUser());
                String srcImg = minioService.generatePresignedUrl(srcImgPath);
                List<String> list = setParams(dto);
                File file = WaterMarkUtils.addWaterMark(srcImg, srcImgPathUser, null, list);
                String pathUrl = minioService.uploadFile(FileUploadCommonUtils.getMultipartFile(file));
                String s = minioService.generatePresignedUrl(pathUrl);
                Minio minio = new Minio();
                minio.setName(file.getName());
                minio.setUrl(pathUrl);
                minio.setAppPath(s);
                minio.setPath(s);
                fileList.add(minio);
                file.delete();
            }
            return GlobalAjaxJson.success().put("data", fileList);

        } catch (Exception e) {
            log.error("上传文件失败", e);
            return GlobalAjaxJson.error(e.getMessage());
        }
    }

    /**
     * 上传图片添加水印
     * @param file
     * @param dto
     * @return
     */
    @PostMapping("uploadFileFiveImg")
    public GlobalAjaxJson uploadFileFiveImg(MultipartFile file, WaterFileDto dto) {
        try {
            List<String> list = setParams(dto);
            // 添加水印
            File img = WaterMarkUtils.addWaterMark(file, null, null, list);
            String pathUrl = minioService.uploadFile(FileUploadCommonUtils.getMultipartFile(img));
            String s = minioService.generatePresignedUrl(pathUrl);
            Minio minio = new Minio();
            minio.setName(file.getName());
            minio.setUrl(pathUrl);
            minio.setAppPath(s);
            minio.setPath(s);
            // 删除源图片
            img.delete();
            return GlobalAjaxJson.success().put("minio", minio);
        } catch (Exception e) {
            log.error("上传文件失败", e);
            return GlobalAjaxJson.error(e.getMessage());
        }
    }

    /**
     * 设置水印参数
     * @param dto
     * @return
     */
    public List<String> setParams(WaterFileDto dto) {
        List<String> list = new ArrayList<>();
        list.add("事项：" + dto.getItemName());
        list.add("地址：" + dto.getAddress());
        list.add("姓名：" + dto.getUserName());
        list.add("时间：" + LocalDateTime.now());
        list.add("场景：" + dto.getTaskName());
        return list;
    }

    /**
     * 告警图片上传请求（base64格式）
     */
    @PostMapping("uploadAlarmImgToOss")
    public GlobalAjaxJson uploadAlarmImgToOss(@RequestPart(value = "file") MultipartFile file,
                                              @RequestParam("deviceCode") String deviceCode) {
        try {
            // 上传并返回访问地址
            String url = minioService.uploadAlarmImgToOss(file, deviceCode);
            Minio minio = new Minio();
            minio.setName(FileUtils.getName(url));
            minio.setUrl(url);

            String s = minioService.generatePresignedUrl(url);
            minio.setPath(s);
            minio.setAppPath(minioService.generatePresignedUrlApp(url));
            return GlobalAjaxJson.success().put("minio", minio);
        } catch (Exception e) {
            log.error("上传文件失败", e);
            return GlobalAjaxJson.error(e.getMessage());
        }
    }

    /**
     * 判断上传的文件大小
     * @param file
     */
    public void voidImgSize(MultipartFile file) {
        String extension = FileTypeUtils.getExtension(file);
        // 判断文件是否是图片
        if (StringUtils.equalsAnyIgnoreCase(extension, MimeTypeUtils.IMAGE_EXTENSION)) {
            try {
                BufferedImage read = ImageIO.read(file.getInputStream());
                if (ObjectUtils.isEmpty(read)) {
                    throw new GlobalExceptions("图片格式异常，请重新选择！");
                }
                int width = read.getWidth();
                int height = read.getHeight();
                if (width < 100 || height < 50) {
                    throw new GlobalExceptions("图片大小异常，请重新上传！");
                }
            } catch (IOException e) {
                throw new GlobalExceptions("图片格式异常！");
            }
            // 判断上传文件是否符合要求
        } else if (!StringUtils.equalsAnyIgnoreCase(extension, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION)) {
            throw new GlobalExceptions("文件格式异常！");
        } else {
            long size = file.getSize();
            if (size > FileUploadCommonUtils.DEFAULT_MAX_SIZE) {
                throw new GlobalExceptions("文件大小不能超过50M！");
            }
        }

    }

    /**
     * 校验base64的图片文件
     * @param msg
     * @return
     */
    public String JudgePictureType(String msg) {
        String s = "";
        if (msg.contains("base64,")) {
            s = msg.split(";base64,")[1];
        } else {
            s = msg;
        }
        byte[] b = Base64.getDecoder().decode(s);
        String type = "undifend";
        if (0x424D == ((b[0] & 0xff) << 8 | (b[1] & 0xff))) {
            type = "bmp";
        } else if (0x8950 == ((b[0] & 0xff) << 8 | (b[1] & 0xff))) {
            type = "png";
        } else if (0xFFD8 == ((b[0] & 0xff) << 8 | (b[1] & 0xff))) {
            type = "jpg";
        }
        return type;
    }
}
